package home;

import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Uniqueness;

import excepciones.NoSonAmigosException;
import persistencia.DbGrafos;
import modelo.tp5.ConsultasCypher;
import modelo.tp5.Mensaje;
import modelo.tp5.Relacion;
import modelo.tp5.UsuarioDeRedSocial;

public class HomePersistenciaNeo4J {
	
	HomePersistenciaHibernate hph;
	
	public HomePersistenciaNeo4J(HomePersistenciaHibernate elHph){
		this.hph = elHph;
	}
	
	public void anadirAmigo(UsuarioDeRedSocial yo, UsuarioDeRedSocial amigo) {
		GraphDatabaseService graphDb = DbGrafos.getInstance().getGraphDbService();
		try ( Transaction tx = graphDb.beginTx() ){
			
			Index<Node> indexNodo = graphDb.index().forNodes("usuarios");
			
			Node yoNodo = indexNodo.get("nombre_usuario", yo.getNombre_usuario()).getSingle();
			Node amigoNodo = indexNodo.get("nombre_usuario", amigo.getNombre_usuario()).getSingle();
			Relationship relacion = yoNodo.createRelationshipTo( amigoNodo, Relacion.AMIGO );
			tx.success();
		}
	}

	public String consultarGenerico(String laConsulta){
		return ConsultasCypher.ejecutarConsulta(laConsulta,DbGrafos.getInstance().getGraphDbService());
	}
	
	public String consultarTodosAmigos(UsuarioDeRedSocial usuario) {
		return this.consultarGenerico("MATCH n-[:AMIGO]->m where n.nombre_usuario ='"+usuario.getNombre_usuario()+"' RETURN m");
	}
	
	public boolean esAmigoDe(UsuarioDeRedSocial de, UsuarioDeRedSocial a){
		System.out.println("usuario " + de.getNombre_usuario() + "tiene como amigo a " + a.getNombre_usuario()+ " = " +(this.consultarTodosAmigos(de).contains(a.getNombre_usuario())));
		return (this.consultarTodosAmigos(de).contains(a.getNombre_usuario()));
		
	}
	
	public void enviarMensaje(Mensaje mensaje) {
		
		GraphDatabaseService graphDb = DbGrafos.getInstance().getGraphDbService();
		int puede = 0;
		
		if(this.esAmigoDe(mensaje.getDe(), mensaje.getA())){
			puede = 1;
		}
		
		try ( Transaction tx = DbGrafos.getInstance().getGraphDbService().beginTx() ){
			if(puede == 1){
				Index<Node> indexNodo = graphDb.index().forNodes("usuarios");
				Node yoNodo = indexNodo.get("nombre_usuario", mensaje.getDe().getNombre_usuario()).getSingle();
				Node amigoNodo = indexNodo.get("nombre_usuario", mensaje.getA().getNombre_usuario()).getSingle();
				Relationship relacion = yoNodo.createRelationshipTo( amigoNodo, Relacion.MENSAJE);
				relacion.setProperty("de", mensaje.getDe().getNombre_usuario());
				relacion.setProperty("A", mensaje.getA().getNombre_usuario());
				relacion.setProperty("mensaje", mensaje.getMensaje());
				tx.success();
			}else{
				throw new NoSonAmigosException();
			}
		}
	}
	
public void crearUsuario(UsuarioDeRedSocial usuario){
		
		GraphDatabaseService graphDb = DbGrafos.getInstance().getGraphDbService();
				
		try (Transaction tx = graphDb.beginTx()){
			Label label = DynamicLabel.label("Usuario");
			Node usuarioYoNodo = graphDb.createNode(label);
			Index<Node> index = graphDb.index().forNodes("usuarios");
			usuarioYoNodo.setProperty( "nombre_usuario", usuario.getNombre_usuario());
			index.add(usuarioYoNodo, "nombre_usuario", usuario.getNombre_usuario());
			tx.success();
		}
	}

	public String recorridoTransversal(UsuarioDeRedSocial usuario){
		return this.consultarGenerico("");
	}
	
	public String iterarNodos(Path path, String output){
		//no logro mostrar los nodos sin repetir, por eso tengo que chequearlo antes y agregarlos si no estan
		for(Node nodos : path.nodes()){
			if(!output.contains((String) nodos.getProperty("nombre_usuario"))){
			 output += nodos.getProperty("nombre_usuario") + " , ";
			}
		}
		return output;
	}
	
	public String RecorridoTransversal( Node node ){
		 TraversalDescription friendsTraversal = DbGrafos.getInstance().getGraphDbService().traversalDescription()
				 .breadthFirst()
				 .relationships( Relacion.AMIGO);
				 //.evaluator(Evaluators.excludeStartPosition());
		 String res = "";
		 String output = "";
		 for ( Path path : friendsTraversal.traverse(node)){
			 res = this.iterarNodos(path, res);
			 //output += path + "\n";
		 }
		 System.out.println(res);
		 return res;
	}
	
	//https://github.com/neo4j/neo4j/blob/master/community/embedded-examples/src/main/java/org/neo4j/examples/TraversalExample.java
	
	//////////////////ACCESORS/////////////////
	
	public HomePersistenciaHibernate getHph() {
		return hph;
	}

	public void setHph(HomePersistenciaHibernate hph) {
		this.hph = hph;
	}
}